package itdep.common.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;

import javax.faces.component.UIComponent;

@Aspect
public class JSFComponentSecurityAspect {
	private static JSFComponentSecurityChecker securityChecker;

	@Autowired(required = true)
	public void setSecurityChecker(JSFComponentSecurityChecker checker) {
		securityChecker = checker;
	}

	/*
		A point cut to capture all executions of encode methods (encodeBegin, encodeEnd, encodeChildren) of any UIComponent.
		hideComponents is the name of a pointcut. A pointcut is the part of the code that we are going to advise.
		execution means join on method execution
		void UIComponent+.encode*(..)) means any encode method returning void for any class that implements UIComponent
	*/
	@Pointcut("execution(void javax.faces.component.UIComponent+.encode*(..))")
	private void hideComponents() {}

	@Around("hideComponents()")
	public Object hideSecurely(ProceedingJoinPoint joinPoint) throws Throwable {
		//joinPoint args
//		for (Object arg : joinPoint.getArgs()) {
//			System.out.println("Join point arg: " + arg);
//		}
		UIComponent component = (UIComponent) joinPoint.getThis();

		/* If this component is not secured, then allow the encode method of the component to execute. */
		if (!securityChecker.isSecured(component)) {
			return joinPoint.proceed();
		}

		/* Check to see if we are allowed to display the component.
		 * If we are allowed, then proceed as usual.
		 * If not, then don't proceed and setRendered to false.
		 */
		if (securityChecker.isAllowed(component)) {
			return joinPoint.proceed();
		} else {
			component.setRendered(false);
		}
		return joinPoint.proceed();
	}

}